function oControlEngine(engine) {
  this.engine = engine;

}

oControlEngine.prototype = {
  //
  render: function () {
  },
  renderLabel: function (control, data) {
    let control_content = control.find("input");
    control_content.attr("readonly", true);
  },
  // 渲染日历组件
  renderCalendar: function (control, data) {
    // 获得控件主体，外加基础绑定，日历框不允许手工修改，只能点点点，同时针对List模式，需要绑定2个。
    let control_content = control.find("input");

    // 绑定2种日历控件，区分日历框和日历时间狂。
    // 官网：http://www.bootcss.com/p/bootstrap-datetimepicker
    if (data.controlTypeID == "5") {
      // control_content.datetimepicker({
      //   language: "zh-CN",
      //   format: 'yyyy-mm-dd',
      //   weekStart: 1,// 一周从哪一天开始
      //   todayBtn: 1,// 今天的按钮
      //   autoclose: 1,// 选择完日期就关闭，不选择事件
      //   todayHighlight: 1,// 今日高亮
      //   startView: 2,// 面板打开后首先显示的视图，1：小时；2：日；3：月；4：年；5：10年表
      //   minView: 2,// 展开的最小粒度：0：分钟；1：小时；2：日；3：月；4：年；5：10年表
      //   forceParse: 1,// 强制解析，尽可能识别正
      //   bootcssVer: 3
      // }).on('hide', function () {
      //   // 如果 v-model 有 lazy 修饰符的话，则通过如下调用，需要注意的是[0]下标一定要加，而且input只能找到一个。
      //   $(this)[0].dispatchEvent(new Event('change'));
      // });
      // // calInput.on("blur",function () {
      // //   $(this).val("1999-9-9");
      // //   //我们可以主动通知浏览器进行事件分发，让Vue监听到，做法如下：
      // //   // $(this)[0].dispatchEvent(new Event('input'));
      // //   //如果 v-model 有 lazy 修饰符的话，则通过如下调用，需要注意的是[0]下标一定要加，而且input只能找到一个。
      // //   $(this)[0].dispatchEvent(new Event('change'));
      // // });

    } else {
      // control_content.datetimepicker({
      //   language: "zh-CN",
      //   format: 'yyyy-mm-dd hh:ii:ss',
      //   weekStart: 1,
      //   todayBtn: 1,
      //   autoclose: 1,
      //   todayHighlight: 1,
      //   startView: 2,
      //   minView: 0,// 最小粒度是到分钟级，但是展开面板视图是天。
      //   forceParse: 1,
      //   bootcssVer: 3
      // }).on('hide', function () {
      //   // 如果 v-model 有 lazy 修饰符的话，则通过如下调用，需要注意的是[0]下标一定要加，而且input只能找到一个。
      //   $(this)[0].dispatchEvent(new Event('change'));
      // });
    }
  },
  renderDropDownList: function (control, data) {
    let o = this;
    // 配置控件主体对象
    let control_content = {
      control: control.find(".iControl"),
      textBox: $(document.createElement("input")),
      valueBox: control.find(".iControl input"),
    };

    // 配置控件下拉面板对象（此对象可复用）
    let control_panel = {
      control: control.find(".iControlDropDown"),
      searchBox: control.find(".iControlDropDown .Search"),
      clearBox: control.find(".iControlDropDown .Clear"),
      rootBox: control.find(".iControlDropDown .Root"),
      enable: true,
      sequence: 0,
      status: 0, // 0关闭，1开启
    };

    // 主体控件配置
    control_content.control.append(control_content.textBox); // 追加至主体控件
    control_content.textBox.attr("readonly", true);// 显示控件设置为只读
    control_content.valueBox.hide(); // 主体控件的值控件（VUE DOM）设置为隐藏

    // 渲染下拉面板，同时设置返回数据源回调事件。
    this.renderDropPanel(data, control_content, control_panel,
      // LoadBack 加载回调就一次。
      function (result) {
        // 只会而且只能得到一个值。
        if (result.content.queryData.length == 1) {
          // 只会得到一个值，赋给show ui控件。
          control_content.textBox.val(result.content.queryData[0][data.controlSourceText]);
        }
        // 如果是层级结构 且 值盒子为0，则填充为Root，表示为根。
        else if (result.content.parentModel && control_content.valueBox.val() == "0") {
          control_content.textBox.val("Root");
        }
        // 如果没有数据 且 控件本身有值 则 说明关联表中已经不存在该数据，问题很严重，应当异常提醒。
        else if (!o.engine.tools.IsNullOrEmpty(control_content.valueBox.val())) {
          // 弹出提示
          control_content.textBox.val("N/A: " + control_content.valueBox.val());
        }
        // console.log("loadback:" + JSON.stringify(result));
      },
      // Item Click Back 选项单击回调，但是只有当没有下拉数据时点击面板弹出才触发该事件。
      function (text, value) {
        // 追加到UI层
        control_content.textBox.val(text);
        // 追加到VUE DOM
        control_content.valueBox.val(value);
        $(control_content.valueBox)[0].dispatchEvent(new Event('change'));
      }
    );
  },
  /**
   * 渲染异步复选框
   *
   * @author Marco Yang
   * @version 1.0.0.0
   * @since Created in 2019-05-09 21:24
   */
  renderMultipleDownList: function (control, data) {
    let o = this;
    // 配置控件主体对象
    let control_content = {
      control: control.find(".iControl"),
      listBox: $(document.createElement("div")),
      valueBox: control.find(".iControl input"),
    };

    // 配置控件下拉面板对象（此对象可复用）
    let control_panel = {
      control: control.find(".iControlDropDown"),
      searchBox: control.find(".iControlDropDown .Search"),
      clearBox: control.find(".iControlDropDown .Clear"),
      rootBox: control.find(".iControlDropDown .Root"),
      enable: true,
      sequence: 0,
      status: 0, // 0关闭，1开启
    };

    // 主体控件配置
    control_content.control.append(control_content.listBox); // 追加至主体控件
    control_content.listBox.addClass("ListBox");// 追加List样式
    control_content.valueBox.hide(); // 主体控件的值控件（VUE DOM）设置为隐藏

    // 设置关闭按钮事件，禁用时因为X被隐藏，所以就算绑定事件也没事，压根点不到，哈哈哈。
    control_content.listBox.on("click", ".icon", function () {
      let removeValue = $(this).attr("value");
      let newValue = "," + control_content.valueBox.val() + ",";
      newValue = newValue.replace("," + removeValue + ",", ",");
      // 去掉头部的逗号[,]
      if (newValue.length > 1) {
        newValue = newValue.substring(1);
      }
      // 去掉结尾的逗号[,]
      if (newValue.substring(newValue.length - 1) == ",") {
        newValue = newValue.substring(0, newValue.length - 1);
      }
      control_content.valueBox.val(newValue);
      $(control_content.valueBox)[0].dispatchEvent(new Event('change'));
      // 移除对象
      $(this).parent().remove();
    });

    // 渲染下拉面板，同时设置返回数据源回调事件。
    this.renderDropPanel(data, control_content, control_panel,
      // LoadBack 加载回调就一次。
      function (result) {
        $(control_content.valueBox.val().split(",")).each(function (index, value) {
          let cellData = $.grep(result.content.queryData, function (curr, i) {
            return curr[data.controlSourceValue] == value;
          });
          // 如果是层级 且 value = 0 则填充根节点。
          if (result.content.parentModel && value == 0) {
            control_content.listBox.append("<div><span class='text'>Root</span><span class='icon iconguanbi'value='0'></span></div>");
          } else {
            // 默认未找到，如果有数据则进行替换，然后赋值。
            let cellText = "N/A: " + value;
            if (cellData.length == 1) {
              cellText = cellData[0][data.controlSourceText];
            }
            control_content.listBox.append("<div><span class='text'>" + cellText + "</span><span class='icon iconguanbi'value='" + value + "'></span></div>");
          }
        });
      },
      // Item Click Back 单击回调，但是只有当没有下拉数据时点击面板弹出才触发该事件。
      function (text, value) {
        // 判断是否已存在
        if (("," + control_content.valueBox.val() + ",").indexOf("," + value + ",") == -1) {
          // 追加到UI层
          control_content.listBox.append("<div><span class='text'>" + text + "</span><span class='icon iconguanbi'value='" + value + "'></span></div>");
          // 追加到VUE DOM
          let listValue = control_content.valueBox.val();
          listValue = listValue.length > 0 ? listValue + "," + value : value;
          control_content.valueBox.val(listValue);
          $(control_content.valueBox)[0].dispatchEvent(new Event('change'));
        } else {
          o.engine.tips.warning(text + " 已被选取，请勿重复选择。");
        }
      }
    );

  },
  /**
   * 通用下拉面板，适用于所有需要下拉的控件。
   *
   * @author Marco Yang
   * @version 1.0.0.0
   * @since Created in 2019-05-09 21:28
   */
  renderDropPanel: function (data, content, panel, loadback, clickback) {
    let o = this;
    // 确保控件请求前已经满足属性要求
    if (!this.engine.tools.IsNullOrEmpty(data.controlSourceID)
      && !this.engine.tools.IsNullOrEmpty(data.controlSourceText)
      && !this.engine.tools.IsNullOrEmpty(data.controlSourceValue)
      && !this.engine.tools.IsNullOrEmpty(data.controlSourceOrder)) {

      // 根据value渲染数据，并抽取数据，前提是有数据值，没有则不发起 LoadBack 加载回调。
      if (!this.engine.tools.IsNullOrEmpty(content.valueBox.val())) {
        let searchValue = [];
        $(content.valueBox.val().split(",")).each(function (index, item) {
          searchValue.push(item);
        });
        let control_request_celldata = [{name: data.controlSourceText},
          {name: data.controlSourceValue, searchKey: "IN", searchValue: searchValue}];
        // 触发load加载回调，只有有数据，才有触发的必要，否则都是空，触发个毛线。
        this.renderRequest({
          cellData: control_request_celldata,
          config: data,
          model: "standard", // 模式设置为【标准】，否则在层级模式下会找不到匹配项目，因为根据父ID筛选了过滤条件以后，只会返回一条数据。。。
          callback: function (result) {
            // 加载回调，针对不同控件，由主控件自由发挥。
            if (loadback) {
              loadback(result);
            }
          }
        });
      }

      // 非禁用才触发
      if (!data.disabled) {
        content.control.on("click", function () {
          // 展开面板，为了适应复选框，完美的写法如下，需要+空字符串转字符串。
          if (($(event.target).attr("class") + "").indexOf("iconguanbi") == -1) {
            let panelWidth = content.control.width() + 29;
            // console.log("panel width:" + panelWidth);
            panel.control.css("width", panelWidth);
            // panel.control.attr("lllll", panelWidth);
            panel.control.slideDown(300, function () {
              panel.status = 1; //展开后变为1
              panel.searchBox.focus();
            });
          }

          // 只有数据为空的时候，点击click才会重新启动。
          // if (panel.control.find(".Item").length == 0) {
          if (data.refresh) {
            // 默认根盒子隐藏，后面满足条件才展开。
            panel.rootBox.hide();

            panel.control.find(".Item").remove();
            let control_request_celldata = [{name: data.controlSourceText}, {name: data.controlSourceValue}];
            // 是否存在-1
            let isExistNoValue = false;
            // 循环 关联数据 对查询数据进行过滤

            o.renderRequest({
              cellData: control_request_celldata,
              config: data,
              callback: function (result) {
                // 如果是层级模式
                if (result.content.parentModel) {
                  // 如果是层级模式，则隐藏查询框
                  panel.searchBox.hide();
                  // 层级模式下，且关联对象都不为-1，启动根节点设置，默认：0
                  if (!isExistNoValue) {
                    panel.rootBox.show();
                    // panel.control.append("<div class='Item Root' value='0'>===Root===</div>");
                  }
                }

                $(result.content.queryData).each(function (index, cell) {
                  // 识别级别，为什么只处理这一段，因为层级模式下，不能搜索，只能选择，故只有这里才有作用。
                  let levelClass = "";
                  // let currItem = ""; // 层级数据源的特性，针对选中的项会高亮，这在标准模式下不能实现，因为只能返回30行，默认加载大概率不会找到选中值。
                  let itemValue = cell[data.controlSourceValue];
                  // 如果存在级别，则说明当前是层级模式
                  if (!o.engine.tools.IsNullOrEmpty(cell["ParentLevel"])) {
                    levelClass = " level_" + cell["ParentLevel"];
                  }
                  // 循环valueBox，同时适配单选和复选下拉框的数据源。这个功能主要用于实现下拉框中显示选中的项目，后期加上。
                  // $(content.valueBox.val().split(",")).each(function (index, item) {
                  //   if (itemValue == item) {
                  //     currItem = " Item_Curr";
                  //   }
                  // });
                  // panel.control.append("<div class='Item" + currItem + levelClass + "' value='" + itemValue + "'>" + cell[data.controlSourceText] + "</div>");
                  panel.control.append("<div class='Item" + levelClass + "' value='" + itemValue + "'>" + cell[data.controlSourceText] + "</div>");
                });

                // 刷新成功以后标记为false
                data.refresh = false;
              }
            });
          }
        });

        // 下拉内容选择事件
        panel.control.on("click", ".Item", function () {
          // 查询回调，针对不同控件，由主控件自由发挥。
          if (clickback) {
            let text = $(this).text();
            let value = $(this).attr("value");
            clickback(text, value);
          }
        });

        // 根节点事件
        panel.rootBox.on("click", function () {
          // 查询回调，针对不同控件，由主控件自由发挥。
          if (clickback) {
            clickback("Root", 0);
          }
        });

        // // 下拉内容输入框失去焦点事件
        // panel.searchBox.on("blur", function () {
        //   setTimeout(function () {
        //     panel.control.slideUp(200);
        //   }, 200);
        // });

        // 鼠标单击事件，主要为了配合自适应收缩面板。
        $(document).on("mousedown", function (event) {
          var e = event;
          var x = e.pageX || e.clientX + document.body.scroolLeft;
          var y = e.pageY || e.clientY + document.body.scrollTop;
          var ele = document.elementFromPoint(x, y);
          // 只有面板状态等于1的情况下 并且 不等于 查询面板（此处需要原始DOM比较才行，$()对象以后就对不上了）才隐藏面板
          if (panel.status == 1 && ele != panel.searchBox.get(0)) {
            setTimeout(function () {
              panel.status = 0;
              panel.control.slideUp(200);
            }, 200);
          }
        });

        // 技术文档：https://www.cnblogs.com/lonhon/p/7643095.html
        // 声明一个标记panel.enable，在compositionstart、compositionend两个事件过程之间的时候flag值为false，在input事件中通过flag的值来判断当前输入的状态。
        panel.searchBox.on('compositionstart', function () {
          panel.enable = false;
        })
        panel.searchBox.on('compositionend', function () {
          panel.enable = true;
        })
        panel.searchBox.on('input', function () {
          let _this = this;
          setTimeout(function () {
            if (panel.enable) {
              // 更新当前值
              let control_request_celldata = [{
                name: data.controlSourceText,
                searchKey: "LIKE",
                searchValue: [$(_this).val()]
              }, {name: data.controlSourceValue}];
              // 循环 关联数据 对查询数据进行过滤

              // 抽取数据，并触发回调。
              o.renderRequest({
                cellData: control_request_celldata,
                config: data,
                callback: function (result) {
                  // 防止因为异步造成先请求的数据最后才返回导致的查询异常，所以对顺序进行判定。
                  if (result.status.sequenceIndex > panel.sequence) {
                    // 更新序列号
                    panel.sequence = result.status.sequenceIndex;
                    // 移除之前创建的
                    panel.control.find(".Item").remove();
                    // 追加数据
                    $(result.content.queryData).each(function (index, cell) {
                      panel.control.append("<div class='Item' value='" + cell[data.controlSourceValue] + "'>" + cell[data.controlSourceText] + "</div>");
                    });
                  }
                }
              });
            }
          }, 0);
        });

        panel.clearBox.on("click", function () {
          if (content.textBox) {
            content.textBox.val("");
          } else {
            content.listBox.html("");
          }
          // 标记为空，触发验证自动控件。
          content.valueBox.val("");
          $(content.valueBox)[0].dispatchEvent(new Event('change'));
        })
        ////////////////////////////////////////////////////////
      }
    }
  },
  // 渲染请求数据，有一些控件是需要获取数据源的。
  renderRequest: function (data) {
    let o = this;
    // 请求后台八爪鱼API框架。
    this.engine.request.api.post("/Octopus/Engine/List", {
        id: data.config.controlSourceID,
        // 当 data.model 不存在时，采用树状请求模式，存在值时，采用标准模式。
        parentKey: data.model == undefined ? data.config.controlSourceParentKey : null,
        parentValue: data.model == undefined ? data.config.controlSourceParentValue : null,
        orderData: data.config.controlSourceOrder,
        cellData: data.cellData,
      },
      // 处理回调事件，通过分析data.status.code的状态来实现。
      function (result) {
        if (result.status.code == 200) {
          // 回调
          if (data.callback) {
            data.callback(result);
          }
        } else {
          o.engine.tips.error(result);
        }
      });
  },
}

export {
  oControlEngine
}


